package ml;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

public class MLSimulator {

	/**
	 * @param args1
	 *            data file name
	 * @param args2
	 *            skip lines
	 * @param args3
	 *            max read lines
	 */
	public static void main(String[] args) {
		if (args.length != 7) {
			System.err.println("Parameters are invalid.");
			System.exit(-1);
		}

		boolean is_train = true;
		StrongClassifer rise_strongClassifier = new StrongClassifer();
		StrongClassifer drop_strongClassifier = new StrongClassifer();
		try {
			System.out.println("Start loading offline strong classifiers ...");
			rise_strongClassifier.load(args[5]);
			drop_strongClassifier.load(args[6]);
			is_train = false;
			System.out.println("Load offline strong classifiers successfully!");
		} catch (IOException e) {
			is_train = true;
			System.out.println("Cannot load offline strong classifiers!");
		}

		System.out.println("Start loading samples ...");
		SampleDataReader sampleLoader = new SampleDataReader(args[0]);
		ArrayList<Double> prices = sampleLoader.get_prices();
		System.out.println("Samples number: " + prices.size());
		System.out.println("Finished loading samples!\n");

		System.out.println("Start calculating labels ...");
		LabelMaker labelMaker = new LabelMaker(MLConstants.TIME_INTERVAL, MLConstants.MIN_PROFIT,
						MLConstants.MAX_LOSS);
		int label_begin = 0;
		int label_num = prices.size() - label_begin - MLConstants.TIME_INTERVAL;
		ArrayList<Boolean> rise_labels = labelMaker
						.calculate(prices, label_begin, label_num, false);
		ArrayList<Boolean> drop_labels = labelMaker.calculate(prices, label_begin, label_num, true);
		System.out.println("Finished calculating labels!\n");

		System.out.println("Statistics of RISE situation!");
		countLabels(rise_labels);
		System.out.println("Statistics of DROP situation!");
		countLabels(drop_labels);

		System.out.println("Start generating training samples ...");
		ArrayList<SampleData> usefulSamples = new ArrayList<SampleData>(label_num);
		for (int i = 0; i < label_num; ++i) {
			usefulSamples.add(sampleLoader.get_samples().get(label_begin + i));
		}

		TrainSampleMaker rise_trainSampleMaker = new TrainSampleMaker(usefulSamples, rise_labels,
						MLConstants.TRAINING_SAMPLES_RATE, is_train, Integer.valueOf(args[2]),
						Integer.valueOf(args[3]));
		TrainSampleMaker drop_trainSampleMaker = new TrainSampleMaker(usefulSamples, drop_labels,
						MLConstants.TRAINING_SAMPLES_RATE, is_train, Integer.valueOf(args[2]),
						Integer.valueOf(args[3]));
		System.out.println("Finished generating training samples!\n");

		if (is_train) {
			System.out.println("Start training samples ...");
			rise_strongClassifier = AdaBoostTrainer.train(
							rise_trainSampleMaker.get_train_samples(),
							rise_trainSampleMaker.get_train_labels(), MLConstants.TRAINING_CYCLES);
			drop_strongClassifier = AdaBoostTrainer.train(
							drop_trainSampleMaker.get_train_samples(),
							drop_trainSampleMaker.get_train_labels(), MLConstants.TRAINING_CYCLES);
			System.out.println("Finished training samples!\n");

			System.out.println("Start dumping offline strong classifiers ...");
			rise_strongClassifier.dump(args[5]);
			drop_strongClassifier.dump(args[6]);
			System.out.println("Dump strong classifiers successfully!");
		}

		System.out.println("Start calculating labels of test samples ...");
		ArrayList<Double> test_prices_front = new ArrayList<Double>(rise_trainSampleMaker
						.get_test_labels_front().size());
		ArrayList<Double> test_prices_end = new ArrayList<Double>(rise_trainSampleMaker
						.get_test_labels_end().size());

		ArrayList<Boolean> rise_calTestLabels_front = new ArrayList<Boolean>(rise_trainSampleMaker
						.get_test_labels_front().size());
		ArrayList<Boolean> drop_calTestLabels_front = new ArrayList<Boolean>(drop_trainSampleMaker
						.get_test_labels_front().size());
		for (SampleData aTestSample : rise_trainSampleMaker.get_test_samples_front()) {
			test_prices_front.add(aTestSample.get_price());
			rise_calTestLabels_front.add(rise_strongClassifier.judge(aTestSample.get_feature()));
		}
		for (SampleData aTestSample : drop_trainSampleMaker.get_test_samples_front()) {
			drop_calTestLabels_front.add(drop_strongClassifier.judge(aTestSample.get_feature()));
		}
		ArrayList<Boolean> rise_calTestLabels_end = new ArrayList<Boolean>(rise_trainSampleMaker
						.get_test_labels_end().size());
		ArrayList<Boolean> drop_calTestLabels_end = new ArrayList<Boolean>(drop_trainSampleMaker
						.get_test_labels_end().size());
		for (SampleData aTestSample : rise_trainSampleMaker.get_test_samples_end()) {
			test_prices_end.add(aTestSample.get_price());
			rise_calTestLabels_end.add(rise_strongClassifier.judge(aTestSample.get_feature()));
		}
		for (SampleData aTestSample : drop_trainSampleMaker.get_test_samples_end()) {
			drop_calTestLabels_end.add(drop_strongClassifier.judge(aTestSample.get_feature()));
		}
		System.out.println("Finished calculating labels of samples!\n");

		System.out.println("Start calculating tradings ...");
		Trading trading = new Trading(10000.0, MLConstants.DECISION_TIME,
						MLConstants.DECISION_RATE, MLConstants.STOP_LOSS, MLConstants.TAKE_PROFIT,
						MLConstants.MIN_LEVERAGE);
		trading.Update(test_prices_front, rise_calTestLabels_front, drop_calTestLabels_front, true);
		trading.Update(test_prices_end, rise_calTestLabels_end, drop_calTestLabels_end, true);
		ArrayList<Double> assets = trading.get_assets();
		ArrayList<Double> buy_vols = trading.get_buy_vols();
		ArrayList<Double> sell_vols = trading.get_sell_vols();
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(args[4]));
			util.DataUtil.OutputArray(bw, assets, 0, assets.size());
			util.DataUtil.OutputArray(bw, buy_vols, 0, assets.size());
			util.DataUtil.OutputArray(bw, sell_vols, 0, assets.size());			
			bw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("Finished calculating tradings!\n");

	}

	private static void countLabels(ArrayList<Boolean> labels) {
		int pos = 0;
		int neg = 0;
		for (Boolean element : labels) {
			if (element) {
				++pos;
			} else {
				++neg;
			}
		}

		System.out.println("Positive labels:\t" + pos);
		System.out.println("Negtive labels:\t" + neg);
		System.out.println("All labels number:\t" + labels.size());
	}
}
